# LeetCode 130、被围绕的区域

# 一、题目描述

给你一个 m x n 的矩阵 board ,由若干字符 'X''O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O''X' 填充。

img

# 二、题目解析

# 三、参考代码

# 1、Java 代码

// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// https://leetcode.cn/problems/surrounded-regions/
class Solution {
    public void solve(char[][] board) {

        // 矩阵的行数
        int m = board.length;

        // 矩阵的列数
        int n = board[0].length;

        // 利用两个 for 循环,遍历矩阵中的一些特殊的单元格,将它们赋值为 N
        // 特殊的单元格:必然是从边界处开始的
        for (int i = 0; i < m; i++){

            for (int j = 0; j < n; j++){

                // i == 0:表示在第 0 行,处于边界位置
                // j == 0:表示在第 0 列,处于边界位置
                // i == (m - 1):表示在最后一行,处于边界位置
                // j == (n - 1):表示在最后一列,处于边界位置
                if (i == 0 || j == 0 || i == (m - 1) || j == (n - 1)){

                    // 从这些单元格开始向腹部延伸下去,找到所有和边界单元格想通的那些 O
                    dfs(board, i, j);
                }
            }
        }

        // 第二个 for 循环,开始修改
        for (int i = 0; i < m; i++){

            for (int j = 0; j < n; j++){

                // board[i][j] == 'O' 表示无法从边界格子中延伸过来
                // 表示被 'X' 围绕的区域
                if (board[i][j] == 'O'){

                    // 修改为 X
                   board[i][j] = 'X';
                }

                // board[i][j] == 'N' 表示是从边界格子中延伸过来
                if (board[i][j] == 'N'){

                    // 修改为 O
                   board[i][j] = 'O';
                }

                
            }
        }



    }

    public void dfs(char[][] board, int i, int j) { 

        // dfs搜索、递归终止条件
        // i < 0 ,越界
        // j < 0 ,越界
        // i >= board.length ,越界
        // j >= board[0].length ,越界
        // board[i][j] == X ,不需要继续搜索下去
        // board[i][j] == N ,这个格子已经被访问过,不需要继续搜索下去
        if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] == 'X' || board[i][j] == 'N') {

            return ;
            
        }

        // 否则说明当前单元格是 O,最后需要保留下来的那种
        // 将当前单元格置为 N ,避免其它格子 dfs 过程中又把它加入到计算中
        board[i][j] = 'N';

        // 在当前单元格的四个方向开始搜索
        // 上:( 0 , -1 )
        // 下:( 0 , 1 )
        // 左:( -1 , 0 )
        // 右:( 1 , 0 )

        // dx 为行的方向数组
        int dx[] = { -1 , 1 , 0 , 0 };

        // dy 为行的方向数组
        int dy[] = { 0 , 0 , -1 , 1 };

        // 朝着这四个方向开始延伸搜索下去
        for (int index = 0; index < 4; index++) {

            // 下一个即将去搜索网格的横坐标
            int next_i = i + dx[index];

            // 下一个即将去搜索网格的纵坐标
            int next_j = j + dy[index];

            // 继续搜索
            dfs(board,next_i,next_j);

        }

    }
}

# **2、**C++ 代码

class Solution {
public:
    void solve(vector<vector<char>>& board) {

        // 矩阵的行数
        int m = board.size();

        // 矩阵的列数
        int n = board[0].size();

        // 利用两个 for 循环,遍历矩阵中的一些特殊的单元格,将它们赋值为 N
        // 特殊的单元格:必然是从边界处开始的
        for (int i = 0; i < m; i++){

            for (int j = 0; j < n; j++){

                // i == 0:表示在第 0 行,处于边界位置
                // j == 0:表示在第 0 列,处于边界位置
                // i == (m - 1):表示在最后一行,处于边界位置
                // j == (n - 1):表示在最后一列,处于边界位置
                if (i == 0 || j == 0 || i == (m - 1) || j == (n - 1)){

                    // 从这些单元格开始向腹部延伸下去,找到所有和边界单元格想通的那些 O
                    dfs(board, i, j);
                }
            }
        }

        // 第二个 for 循环,开始修改
        for (int i = 0; i < m; i++){

            for (int j = 0; j < n; j++){

                // board[i][j] == 'O' 表示无法从边界格子中延伸过来
                // 表示被 'X' 围绕的区域
                if (board[i][j] == 'O'){

                    // 修改为 X
                   board[i][j] = 'X';
                }

                // board[i][j] == 'N' 表示是从边界格子中延伸过来
                if (board[i][j] == 'N'){

                    // 修改为 O
                   board[i][j] = 'O';
                }

                
            }
        }

    }

public:
    void dfs(vector<vector<char>>& board, int i, int j) { 

        // dfs搜索、递归终止条件
        // i < 0 ,越界
        // j < 0 ,越界
        // i >= board.length ,越界
        // j >= board[0].length ,越界
        // board[i][j] == X ,不需要继续搜索下去
        // board[i][j] == N ,这个格子已经被访问过,不需要继续搜索下去
        if (i < 0 || j < 0 || i >= board.size() || j >= board[0].size() || board[i][j] == 'X' || board[i][j] == 'N') {

            return ;
            
        }

        // 否则说明当前单元格是 O,最后需要保留下来的那种
        // 将当前单元格置为 N ,避免其它格子 dfs 过程中又把它加入到计算中
        board[i][j] = 'N';

        // 在当前单元格的四个方向开始搜索
        // 上:( 0 , -1 )
        // 下:( 0 , 1 )
        // 左:( -1 , 0 )
        // 右:( 1 , 0 )

        // dx 为行的方向数组
        int dx[4] = { -1 , 1 , 0 , 0 };

        // dy 为行的方向数组
        int dy[4] = { 0 , 0 , -1 , 1 };

        // 朝着这四个方向开始延伸搜索下去
        for (int index = 0; index < 4; index++) {

            // 下一个即将去搜索网格的横坐标
            int next_i = i + dx[index];

            // 下一个即将去搜索网格的纵坐标
            int next_j = j + dy[index];

            // 继续搜索
            dfs(board,next_i,next_j);

        }

    }

};

# 3、Python 代码

# 登录 AlgoMooc 官网获取更多算法图解
# https://www.algomooc.com
# 作者:程序员吴师兄
# 代码有看不懂的地方一定要私聊咨询吴师兄呀
# https://leetcode.cn/problems/surrounded-regions/
class Solution:
    def solve(self, board: List[List[str]]) -> None:

        # 矩阵的行数
        m = len(board)

        # 矩阵的列数
        n = len(board[0])

        # 利用两个 for 循环,遍历矩阵中的一些特殊的单元格,将它们赋值为 N
        # 特殊的单元格:必然是从边界处开始的
        for  i in range(0 , m ) : 

            for j in range( 0 , n ):

                # i == 0:表示在第 0 行,处于边界位置
                # j == 0:表示在第 0 列,处于边界位置
                # i == (m - 1):表示在最后一行,处于边界位置
                # j == (n - 1):表示在最后一列,处于边界位置
                if  i == 0 or j == 0 or i == (m - 1) or j == (n - 1) :

                    # 从这些单元格开始向腹部延伸下去,找到所有和边界单元格想通的那些 O
                    self.dfs(board, i, j)
   

        # 第二个 for 循环,开始修改
        for  i in range(0 , m ) : 

            for j in range( 0 , n ):

                # board[i][j] == 'O' 表示无法从边界格子中延伸过来
                # 表示被 'X' 围绕的区域
                if  board[i][j] == 'O' : 

                    # 修改为 X
                   board[i][j] = 'X'
                

                # board[i][j] == 'N' 表示是从边界格子中延伸过来
                if  board[i][j] == 'N' : 

                    # 修改为 O
                   board[i][j] = 'O'

    def dfs(self, board: List[List[str]], i : int , j : int ) -> None:
        # dfs搜索、递归终止条件
        # i < 0 ,越界
        # j < 0 ,越界
        # i >= board.length ,越界
        # j >= board[0].length ,越界
        # board[i][j] == X ,不需要继续搜索下去
        # board[i][j] == N ,这个格子已经被访问过,不需要继续搜索下去
        if  i < 0 or j < 0 or i >= len(board) or j >= len(board[0]) or board[i][j] == 'X' or board[i][j] == 'N' : 

            return 
            

        # 否则说明当前单元格是 O,最后需要保留下来的那种
        # 将当前单元格置为 N ,避免其它格子 dfs 过程中又把它加入到计算中
        board[i][j] = 'N'

        # 在当前单元格的四个方向开始搜索
        # 上:( 0 , -1 )
        # 下:( 0 , 1 )
        # 左:( -1 , 0 )
        # 右:( 1 , 0 )
        # 朝着这四个方向开始延伸搜索下去
        for dx, dy in ((0,1), (1,0), (0,-1), (-1,0)):

            # 下一个即将去搜索网格的横坐标
            next_i = i + dx

            # 下一个即将去搜索网格的纵坐标
            next_j = j + dy

            # 继续搜索
            self.dfs(board,next_i,next_j)

# 四、复杂度分析

时间复杂度:O(n×m),其中 n 和 m 分别为矩阵的行数和列数。深度优先搜索过程中,每一个点至多只会被标记一次。

空间复杂度:O(n×m),其中 n 和 m 分别为矩阵的行数和列数。主要为深度优先搜索的栈的开销。